package com.ruoyi.generator.service.impl;

import java.io.ByteArrayOutputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipOutputStream;

import com.ruoyi.common.constant.ServiceConstants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.aes.AESEncryptor;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.generator.domain.Database;
import com.ruoyi.generator.gen.GenUtils;
import com.ruoyi.generator.mapper.DatabaseMapper;
import com.ruoyi.generator.sdk.MySqlConnectionClient;
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.mapper.SysConfigMapper;
import com.ruoyi.system.mapper.SysUserMapper;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import com.ruoyi.generator.mapper.GeneratedRecordsMapper;
import com.ruoyi.generator.domain.GeneratedRecords;
import com.ruoyi.generator.service.IGeneratedRecordsService;

/**
 * 代码生产记录Service业务层处理
 *
 * @author ruoyi
 * @date 2024-12-26
 */
@Service
public class GeneratedRecordsServiceImpl implements IGeneratedRecordsService {
    @Autowired
    private GeneratedRecordsMapper generatedRecordsMapper;

    @Autowired
    private DatabaseMapper databaseMapper;

    @Autowired
    private SysConfigMapper configMapper;
    @Autowired
    private AESEncryptor aesEncryptor;

    @Autowired
    private SysUserMapper sysUserMapper;

    /**
     * 查询代码生产记录
     *
     * @param id 代码生产记录主键
     * @return 代码生产记录
     */
    @Override
    public GeneratedRecords selectGeneratedRecordsById(Long id) {
        return generatedRecordsMapper.selectGeneratedRecordsById(id);
    }


    //提交审核
    @Override
    public int toExamine(Long id) {
        GeneratedRecords generatedRecords = generatedRecordsMapper.selectGeneratedRecordsById(id);
        if (generatedRecords == null || !generatedRecords.getGenStatus().equals(ServiceConstants.GEN_STATIC_TESTED)) {
            throw new ServiceException("提审失败，请刷新后重试！");
        }
        generatedRecords.setGenStatus(ServiceConstants.GEN_STATIC_PENDING_REVIEW);
        generatedRecords.setGenStatusInfo("已提交，等待管理员审核！");
        int i = generatedRecordsMapper.updateGeneratedRecords(generatedRecords);
        return i;
    }

    /**
     * 审核通过
     * @param id
     * @return
     */
    @Override
    public int examineSuccess(Long id) {
        GeneratedRecords generatedRecords = generatedRecordsMapper.selectGeneratedRecordsById(id);
        if (generatedRecords == null || !generatedRecords.getGenStatus().equals(ServiceConstants.GEN_STATIC_PENDING_REVIEW)) {
            throw new ServiceException("审核失败，请刷新后重试！");
        }
        CreateProdSQL(generatedRecords); //生产库创建SQL
        generatedRecords.setGenStatus(ServiceConstants.GEN_STATIC_APPROVED);
        generatedRecords.setGenStatusInfo("审核通过！");
        generatedRecords.setGenReviewer(SecurityUtils.getLoginUser().getUser().getUserName());
        int i = generatedRecordsMapper.updateGeneratedRecords(generatedRecords);
        return i;
    }

    //驳回审核
    @Override
    public int toReject(Long id,String message) {
        GeneratedRecords generatedRecords = generatedRecordsMapper.selectGeneratedRecordsById(id);
        if (generatedRecords == null || !generatedRecords.getGenStatus().equals(ServiceConstants.GEN_STATIC_PENDING_REVIEW)) {
            throw new ServiceException("驳回失败，请刷新后重试！");
        }
        generatedRecords.setGenStatus(ServiceConstants.GEN_STATIC_REJECTED);
        generatedRecords.setGenStatusInfo(message);
        generatedRecords.setGenReviewer(SecurityUtils.getLoginUser().getUser().getUserName());
        int i = generatedRecordsMapper.updateGeneratedRecords(generatedRecords);
        return i;
    }


    /**
     * 查看详情
     *
     * @param generatedRecords
     * @return
     */
    @Override
    public AjaxResult check(GeneratedRecords generatedRecords) {
        SysUser sysUser = sysUserMapper.selectUserById(generatedRecords.getUserId());
        generatedRecords.setUsername(sysUser.getUserName());
        if (generatedRecords.getGenStatus().equals(ServiceConstants.GEN_STATIC_DRAFT)) {
            //草稿
            return AjaxResult.success(generatedRecords);
        } else if (generatedRecords.getGenStatus().equals(ServiceConstants.GEN_STATIC_SUBMITTED)) {
            //测试中
            return AjaxResult.success(generatedRecords);
        } else if (generatedRecords.getGenStatus().equals(ServiceConstants.GEN_STATIC_TESTED)) {
            //测试通过
            MySqlConnectionClient testClient = getTestPriClient(generatedRecords);
            List<Map<String, Object>> list = new ArrayList<>();
            try {
                list = testClient.queryList();
            } catch (SQLException e) {
                throw new ServiceException("查询列表错误！" + e.getMessage());
            }
            return AjaxResult.success(generatedRecords).put("tableList", list);
        } else if (generatedRecords.getGenStatus().equals(ServiceConstants.GEN_STATIC_PENDING_REVIEW)) {
            //待审核
            MySqlConnectionClient testClient = getTestPriClient(generatedRecords);
            List<Map<String, Object>> list = new ArrayList<>();
            try {
                list = testClient.queryList();
            } catch (SQLException e) {
                throw new ServiceException("查询列表错误！" + e.getMessage());
            }
            return AjaxResult.success(generatedRecords).put("tableList", list);
        } else if (generatedRecords.getGenStatus().equals(ServiceConstants.GEN_STATIC_APPROVED)) {
            //已审核
            MySqlConnectionClient prodClient = getProdPriClient(generatedRecords);
            List<Map<String, Object>> list = new ArrayList<>();
            try {
                list = prodClient.queryList();
            } catch (SQLException e) {
                throw new ServiceException("查询列表错误！" + e.getMessage());
            }
            return AjaxResult.success(generatedRecords).put("tableList", list);
        } else if (generatedRecords.getGenStatus().equals(ServiceConstants.GEN_STATIC_REJECTED)) {
            //已驳回
            MySqlConnectionClient testClient = getTestPriClient(generatedRecords);
            List<Map<String, Object>> list = new ArrayList<>();
            try {
                list = testClient.queryList();
            } catch (SQLException e) {
                throw new ServiceException("查询列表错误！" + e.getMessage());
            }
            return AjaxResult.success(generatedRecords).put("tableList", list);
        } else if (generatedRecords.getGenStatus().equals(ServiceConstants.GEN_STATIC_TEST_FAILED)) {
            //测试未通过
            return AjaxResult.success(generatedRecords);
        } else {
            //未知
            throw new ServiceException("错误！未知状态！请联系管理员!");
        }
    }

    @Override
    public byte[] generatorCode(String[] tableNames,Long id, String model) {
        GeneratedRecords generatedRecords = generatedRecordsMapper.selectGeneratedRecordsById(id);
        MySqlConnectionClient prodClient = getProdPriClient(generatedRecords);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(outputStream);
        Map<String,List<Map<String,Object>>> parm=new HashMap<>();
        List<Map<String,Object>> list=new ArrayList<>();
        // TODO 管理后台代码生成
        for (String tableName : tableNames) {
            //查询表信息
            Map<String, String> table = null;
            try {
                table = prodClient.queryTable(tableName);
            } catch (SQLException e) {
                throw new ServiceException("查询表信息失败"+e.getMessage());
            }
            //查询列信息
            List<Map<String, String>> columns = null;
            try {
                columns = prodClient.queryColumns(tableName);
            } catch (SQLException e) {
                throw new ServiceException("查询列信息失败"+e.getMessage());
            }
            //生成代码
            Map<String, Object> map = GenUtils.generatorCodeAdmin(table, columns, zip,model);
            list.add(map);
        }
        parm.put("parm",list);
        //TODO WEB前台代码生成
        GenUtils.generatorCodeWeb(parm,zip);
        IOUtils.closeQuietly(zip);
        return outputStream.toByteArray();
    }

    /**
     * 查询代码生产记录列表
     *
     * @param generatedRecords 代码生产记录
     * @return 代码生产记录
     */
    @Override
    public List<GeneratedRecords> selectGeneratedRecordsList(GeneratedRecords generatedRecords) {
        return generatedRecordsMapper.selectGeneratedRecordsList(generatedRecords);
    }

    /**
     * 新增代码生产记录
     *
     * @param generatedRecords 代码生产记录
     * @return 结果
     */
    @Override
    public int insertGeneratedRecords(GeneratedRecords generatedRecords) {
        generatedRecords.setCreateTime(DateUtils.getNowDate());
        generatedRecords.setCreateBy(SecurityUtils.getUsername());
        return generatedRecordsMapper.insertGeneratedRecords(generatedRecords);
    }

    /**
     * 修改代码生产记录
     *
     * @param generatedRecords 代码生产记录
     * @return 结果
     */
    @Override
    public int updateGeneratedRecords(GeneratedRecords generatedRecords) {
        generatedRecords.setUpdateTime(DateUtils.getNowDate());
        generatedRecords.setUpdateBy(SecurityUtils.getUsername());
        return generatedRecordsMapper.updateGeneratedRecords(generatedRecords);
    }

    /**
     * 批量删除代码生产记录
     *
     * @param ids 需要删除的代码生产记录主键
     * @return 结果
     */
    @Override
    public int deleteGeneratedRecordsByIds(Long[] ids) {
        return generatedRecordsMapper.deleteGeneratedRecordsByIds(ids);
    }

    /**
     * 删除代码生产记录信息
     *
     * @param id 代码生产记录主键
     * @return 结果
     */
    @Override
    public int deleteGeneratedRecordsById(Long id) {
        return generatedRecordsMapper.deleteGeneratedRecordsById(id);
    }



    /**
     * 提交测试逻辑
     *
     * @param generatedRecords 提交测试
     * @return
     */
    @Override
    public int testGeneratedRecords(GeneratedRecords generatedRecords) {
        generatedRecords.setGenStatus(ServiceConstants.GEN_STATIC_SUBMITTED);//保存为测试中
        generatedRecords.setGenStatusInfo("正在SQL！请等待1-3分钟后刷新测试结果！");//保存为测试
        generatedRecords.setUserId(SecurityUtils.getUserId());
        if (generatedRecords.getGenBaseName() == null) {
            generatedRecords.setGenBaseName("base_" + IdUtils.simpleUUID().substring(0, 8));
        }
        SysConfig sysConfigTest = configMapper.checkConfigKeyUnique(ServiceConstants.GEN_CONFIG_DATABASE_TEST);//查询配置中的测试库
        String test = sysConfigTest.getConfigValue();
        Database databaseTest = databaseMapper.selectDatabaseById(Long.valueOf(test));
        if (databaseTest != null) {
            generatedRecords.setTestBaseId(databaseTest.getId());//配置测试库
        } else {
            throw new ServiceException("测试数据库未配置！请联系管理员！");
        }
        SysConfig sysConfigProd = configMapper.checkConfigKeyUnique(ServiceConstants.GEN_CONFIG_DATABASE_PROD);//查询配置中的生产库
        String prod = sysConfigProd.getConfigValue();
        Database database = databaseMapper.selectDatabaseById(Long.valueOf(prod));
        if (database != null) {
            generatedRecords.setMainBaseId(database.getId());//配置生产库
        } else {
            throw new ServiceException("生产数据库未配置！请联系管理员！");
        }

        generatedRecords.setGenStatusInfo("已提交测试！");
        int i = 0;
        if (generatedRecords.getId() != null) {
            i = generatedRecordsMapper.updateGeneratedRecords(generatedRecords);
        } else {
            generatedRecords.setCreateTime(DateUtils.getNowDate());
            generatedRecords.setCreateBy(SecurityUtils.getUsername());
            i = generatedRecordsMapper.insertGeneratedRecords(generatedRecords);
        }
        //  异步执行测试结果
        testSQL(generatedRecords);
        return i;
    }


    //异步执行测试
    @Async("testSQL")
    public void testSQL(GeneratedRecords generatedRecords) {
        StringBuffer message = new StringBuffer();
        // 查询测试库信息
        Long testBaseId = generatedRecords.getTestBaseId();
        Database database = databaseMapper.selectDatabaseById(testBaseId);

        MySqlConnectionClient mySqlConnectionClient = new MySqlConnectionClient.Builder()
                .mySqlIp(database.getBaseIp())//Ip
                .mySqlPort(database.getBasePort())//端口
                .databaseName(database.getBaseName())//数据库名
                .databasePassword(aesEncryptor.decrypt(database.getBasePassword()))//数据库密码
                .databaseUsername(database.getBaseUsername())//数据库用户名
                .build();
        try {
            mySqlConnectionClient.testConnection();
        } catch (SQLException e) {
            message.append("链接测试库" + database.getBaseName() + "失败！" + e.getMessage() + "\n");
            generatedRecords.setGenStatus(ServiceConstants.GEN_STATIC_TEST_FAILED);
            generatedRecords.setGenStatusInfo(message.toString());
            generatedRecordsMapper.updateGeneratedRecords(generatedRecords);
            return;
        }
        // 测试建库
        try {
            mySqlConnectionClient.createDatabase(generatedRecords.getGenBaseName());
        } catch (SQLException e) {
            message.append("创建数据库" + generatedRecords.getGenBaseName() + "失败！" + e.getMessage() + "\n");
            generatedRecords.setGenStatus(ServiceConstants.GEN_STATIC_TEST_FAILED);
            generatedRecords.setGenStatusInfo(message.toString());
            generatedRecordsMapper.updateGeneratedRecords(generatedRecords);
            return;
        }
        MySqlConnectionClient mySqlNewDataBase = new MySqlConnectionClient.Builder()
                .mySqlIp(database.getBaseIp())//Ip
                .mySqlPort(database.getBasePort())//端口
                .databaseName(generatedRecords.getGenBaseName())//数据库名
                .databasePassword(aesEncryptor.decrypt(database.getBasePassword()))//数据库密码
                .databaseUsername(database.getBaseUsername())//数据库用户名
                .build();
        try {
            mySqlNewDataBase.testConnection();
        } catch (SQLException e) {
            message.append("链接已创建的测试库" + generatedRecords.getGenBaseName() + "失败！" + e.getMessage() + "\n");
            generatedRecords.setGenStatus(ServiceConstants.GEN_STATIC_TEST_FAILED);
            generatedRecords.setGenStatusInfo(message.toString());
            generatedRecordsMapper.updateGeneratedRecords(generatedRecords);
            return;
        }
        // 测试SQL执行
        try {
            mySqlNewDataBase.createTablesFromSqlString(generatedRecords.getGenBaseSql());
        } catch (SQLException e) {
            message.append("执行SQL失败！" + e.getMessage() + "\n");
            generatedRecords.setGenStatus(ServiceConstants.GEN_STATIC_TEST_FAILED);
            generatedRecords.setGenStatusInfo(message.toString());
            generatedRecordsMapper.updateGeneratedRecords(generatedRecords);
            return;
        }
        message.append("SQL测试通过！" + "\n");
        generatedRecords.setGenStatus(ServiceConstants.GEN_STATIC_TESTED);
        generatedRecords.setGenStatusInfo(message.toString());
        generatedRecordsMapper.updateGeneratedRecords(generatedRecords);
    }


    /**
     * 审核通过后自动创建库与SQL
     *
     * @param generatedRecords
     */
    public void CreateProdSQL(GeneratedRecords generatedRecords) {
        // 查询主数据库
        Long testBaseId = generatedRecords.getMainBaseId();
        Database database = databaseMapper.selectDatabaseById(testBaseId);
        MySqlConnectionClient mySqlConnectionClient = new MySqlConnectionClient.Builder()
                .mySqlIp(database.getBaseIp())//Ip
                .mySqlPort(database.getBasePort())//端口
                .databaseName(database.getBaseName())//数据库名
                .databasePassword(aesEncryptor.decrypt(database.getBasePassword()))//数据库密码
                .databaseUsername(database.getBaseUsername())//数据库用户名
                .build();
        try {
            mySqlConnectionClient.testConnection();
        } catch (SQLException e) {
            throw new ServiceException("主库链接失败请联系管理员！");
        }
        // 测试建库
        try {
            mySqlConnectionClient.createDatabase(generatedRecords.getGenBaseName());
        } catch (SQLException e) {
            throw new ServiceException("创建数据库" + generatedRecords.getGenBaseName() + "失败！" + e.getMessage() + "\n");
        }
        MySqlConnectionClient mySqlNewDataBase = new MySqlConnectionClient.Builder()
                .mySqlIp(database.getBaseIp())//Ip
                .mySqlPort(database.getBasePort())//端口
                .databaseName(generatedRecords.getGenBaseName())//数据库名
                .databasePassword(aesEncryptor.decrypt(database.getBasePassword()))//数据库密码
                .databaseUsername(database.getBaseUsername())//数据库用户名
                .build();
        try {
            mySqlNewDataBase.testConnection();
        } catch (SQLException e) {
            throw new ServiceException("链接已创建的测试库" + generatedRecords.getGenBaseName() + "失败！" + e.getMessage() + "\n");
        }
        // 测试SQL执行
        try {
            mySqlNewDataBase.createTablesFromSqlString(generatedRecords.getGenBaseSql());
        } catch (SQLException e) {
            throw new ServiceException("执行SQL失败！" + e.getMessage() + "\n");
        }

    }

    /**
     * 获取测试库链接
     *
     * @param generatedRecords
     * @return
     */
    private MySqlConnectionClient getTestClient(GeneratedRecords generatedRecords) {
        Long testBaseId = generatedRecords.getTestBaseId();
        Database database = databaseMapper.selectDatabaseById(testBaseId);
        MySqlConnectionClient mySqlConnectionClient = new MySqlConnectionClient.Builder()
                .mySqlIp(database.getBaseIp())//Ip
                .mySqlPort(database.getBasePort())//端口
                .databaseName(database.getBaseName())//数据库名
                .databasePassword(aesEncryptor.decrypt(database.getBasePassword()))//数据库密码
                .databaseUsername(database.getBaseUsername())//数据库用户名
                .build();
        return mySqlConnectionClient;
    }

    /**
     * 获取测试库链接
     *
     * @param generatedRecords
     * @return
     */
    private MySqlConnectionClient getTestPriClient(GeneratedRecords generatedRecords) {
        Long testBaseId = generatedRecords.getTestBaseId();
        Database database = databaseMapper.selectDatabaseById(testBaseId);
        MySqlConnectionClient mySqlConnectionClient = new MySqlConnectionClient.Builder()
                .mySqlIp(database.getBaseIp())//Ip
                .mySqlPort(database.getBasePort())//端口
                .databaseName(generatedRecords.getGenBaseName())//数据库名
                .databasePassword(aesEncryptor.decrypt(database.getBasePassword()))//数据库密码
                .databaseUsername(database.getBaseUsername())//数据库用户名
                .build();
        return mySqlConnectionClient;
    }
    /**
     * 获取生产库链接
     *
     * @param generatedRecords
     * @return
     */
    private MySqlConnectionClient getProdPriClient(GeneratedRecords generatedRecords) {
        // 查询主数据库
        Long testBaseId = generatedRecords.getMainBaseId();
        Database database = databaseMapper.selectDatabaseById(testBaseId);
        MySqlConnectionClient mySqlConnectionClient = new MySqlConnectionClient.Builder()
                .mySqlIp(database.getBaseIp())//Ip
                .mySqlPort(database.getBasePort())//端口
                .databaseName(generatedRecords.getGenBaseName())//数据库名
                .databasePassword(aesEncryptor.decrypt(database.getBasePassword()))//数据库密码
                .databaseUsername(database.getBaseUsername())//数据库用户名
                .build();

        return mySqlConnectionClient;
    }
    /**
     * 获取生产库链接
     *
     * @param generatedRecords
     * @return
     */
    private MySqlConnectionClient getProdClient(GeneratedRecords generatedRecords) {
        // 查询主数据库
        Long testBaseId = generatedRecords.getMainBaseId();
        Database database = databaseMapper.selectDatabaseById(testBaseId);
        MySqlConnectionClient mySqlConnectionClient = new MySqlConnectionClient.Builder()
                .mySqlIp(database.getBaseIp())//Ip
                .mySqlPort(database.getBasePort())//端口
                .databaseName(database.getBaseName())//数据库名
                .databasePassword(aesEncryptor.decrypt(database.getBasePassword()))//数据库密码
                .databaseUsername(database.getBaseUsername())//数据库用户名
                .build();
        return mySqlConnectionClient;
    }



}
